﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Harkon.AppServer.cOne.Service;
using log4net;
using System.Diagnostics;
using System.Threading;
using System.ServiceModel.Description;

namespace Harkon.AppServer.cOne.Registry
{
    [ServiceBehavior(
        IncludeExceptionDetailInFaults = true,
        InstanceContextMode = InstanceContextMode.Single,
        ConcurrencyMode = ConcurrencyMode.Multiple
        )]
    public class Registry : AbstractService, IRegistry
    {

        private static ILog logger = LogManager.GetLogger(typeof(Registry));
        private Thread serviceHostThread;
        private ServiceHost serviceHost;

        #region IRegistry Members

        private IDictionary<string, ComponentInformation> serviceRegistry = new Dictionary<string, ComponentInformation>();

        public void RegisterComponent(ComponentInformation component)
        {
            if (serviceRegistry.ContainsKey(component.Name))
            {
                throw new Exception("ComponentInformation already registered!");
            }
            serviceRegistry.Add(component.Name, component);
            logger.Info(string.Format("Registered component {0}", component));
        }

        public void UnregisterComponent(string componentName)
        {
            if (!serviceRegistry.ContainsKey(componentName))
            {
                throw new Exception("ComponentInformation is missing!");
            }
            serviceRegistry.Remove(componentName);
            logger.Info(string.Format("Unregistered component {0}", componentName));
        }

        public ComponentInformation[] GetRegisteredComponents()
        {
            return serviceRegistry.Values.ToArray<ComponentInformation>();
        }

        public ComponentInformation GetRegisteredComponentsForName(string componentName)
        {
            return serviceRegistry[componentName];
        }

        public void RegisterService(ServiceName service, object target)
        {
            if (!serviceRegistry.ContainsKey(service.Component))
            {
                throw new Exception("ComponentInformation is missing!");
            }
            ComponentInformation component = serviceRegistry[service.Component];
            component.AddService(service, target);
            logger.Info(string.Format("Registered service {0} in component {1}", service, component));
        }



        public ComponentInformation GetComponentForService(ServiceName service)
        {
            if (!serviceRegistry.ContainsKey(service.Component))
            {
                throw new Exception();
            }

            return serviceRegistry[service.Component];
        }

        public object GetService(ServiceName service)
        {
            if (!serviceRegistry.ContainsKey(service.Component))
            {
                throw new Exception();
            }

            ComponentInformation currentInformation = serviceRegistry[service.Component];
            var query = from neededService in currentInformation.Services.Keys where neededService.Contract.Equals(service.Contract) select neededService;
            ServiceName ret = query.First();
            return currentInformation.Services[ret];
        }

        #endregion

        #region ILifecycleAware Members

        public override bool Init()
        {
            if (base.Init())
            {
                //create service host with this instance as hosted class
                serviceHost = new ServiceHost(this);

                serviceHostThread = new Thread(Run);
                serviceHostThread.Name = "Registry";
                serviceHostThread.IsBackground = true;
                logger.InfoFormat("The registry service host url={0}", serviceHost.BaseAddresses[0].AbsoluteUri);
                logger.Debug("Registry initialized");
                return true;
            }
            return false;
        }

        public override bool Start()
        {
            if (base.Start())
            {
                serviceHostThread.Start();
                logger.Debug("Registry running");
                return true;
            } 
            return false;
        }

        public override bool Stop()
        {
            if (base.Stop())
            {
                lock (this)
                {
                    Monitor.Pulse(this);
                }
                logger.Debug("Registry stopped");
                return true;
            }
            return false;
        }

        #endregion

        #region ServiceHost related

        private void Run()
        {
            //start service host
            try
            {
                serviceHost.Open();
                logger.Info("The registry service host is up and running.");
                lock (this)
                {
                    Monitor.Wait(this);
                }

                logger.Warn("The registry service host is closing...");
                serviceHost.Close();
                logger.Warn("The registry service host is closed!");
            }
            catch (CommunicationException ce)
            {
                logger.Fatal(ce.Message, ce);
                serviceHost.Abort();
            }
        }

        #endregion
    }
}
